import type { DataAttrsItem } from '../../../../../../lib/abstract/base_destructible'
import type { GreasyForkElements } from '../../../../../../types/constants/personalization/greasy_fork'
import type { ComponentStyleIdType } from '../../../../../../types/interfaces'
import type { IScriptData } from '../../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/module/script_processor/types'
import type {
  IScriptRank,
  IStats,
  ScoreLevelType,
} from './types'
import { BaseModule } from '../../../../../../lib/abstract'
import {
  AppStyleCollections,
  ComponentStyleId,
  logger,
  PAGE_ELEMENTS,
  SUPPORTED_PLATFORMS,
} from '../../../../../../types/constants'
import { SYMBOLS } from '../../../../../../types/interfaces'
import { ScriptProcessor } from '../../../../../../user_center/tab/personalization/custom_css/theme/others/greasy_fork/module/script_processor'
import { ConfigManager } from '../../../../../config_manager'
import { StyleManager } from '../../../../../style_manager'
import {
  SCORE_LEVELS,
  SCRIPT_TAG_LABELS,
  TAG_EXCLUSIVE_RULES,
  TAG_MIN_SCORES,
} from './types'

interface Config {
  enabled?: boolean
}

export class GreasyForkScriptValuation extends BaseModule {
  readonly id: string = 'greasy_fork_script_valuation'
  readonly styleId: string = ComponentStyleId[this.name]
  isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: GreasyForkScriptValuation
  private scriptProcessor: ScriptProcessor = ScriptProcessor.getInstance()
  elements: GreasyForkElements = PAGE_ELEMENTS[SUPPORTED_PLATFORMS.GREASY_FORK]
  private readonly CONTAINER_CLASS: string = AppStyleCollections.GreasyFork.SCRIPT_META_CONTAINER
  private readonly dataAttrs: Record<
    'processed' | 'score',
    DataAttrsItem
  > = {
    processed: { type: 'data', name: 'processed-valuation' },
    score: { type: 'attr', name: 'data-script-rating-score' },
  }

  config: Config = {
    enabled: true,
  }

  private globalStats: IStats = {
    maxDailyInstalls: 0,
    maxTotalInstalls: 0,
    maxGoodRatings: 0,
    maxDailyAvgInstalls: 0,
  }

  get name(): ComponentStyleIdType {
    return 'GreasyForkScriptValuation'
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): GreasyForkScriptValuation {
    if (!GreasyForkScriptValuation.instance) {
      GreasyForkScriptValuation.instance = new GreasyForkScriptValuation()
    }
    return GreasyForkScriptValuation.instance
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.scriptProcessor.init()
    this.processAllScriptElements()

    // 注册样式
    StyleManager.getInstance().registerStyle(this.styleId, this.getStyles(), false, true)
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  /**
   * 处理所有脚本元素
   */
  processAllScriptElements(): void {
    // 初始化全局统计数据
    this.initGlobalStats()

    // 处理每个脚本元素
    $(this.scriptProcessor.SCRIPT_LIST_SELECTOR).each((_, element) => {
      this.processScriptElement($(element))
    })
  }

  /**
   * 初始化统计数据
   */
  private initGlobalStats(): void {
    const stats = {
      maxDailyInstalls: 0,
      maxTotalInstalls: 0,
      maxGoodRatings: 0,
      maxDailyAvgInstalls: 0,
    }

    $(this.scriptProcessor.SCRIPT_LIST_SELECTOR).each((_, element) => {
      const $script = $(element)
      const dailyInstalls = Number.parseInt($script.attr('data-script-daily-installs') || '0')
      const totalInstalls = Number.parseInt($script.attr('data-script-total-installs') || '0')
      const goodRating = Number.parseInt($script.find('.good-rating-count').text() || '0')
      const createDays = this.scriptProcessor.calculateDaysSince($script.attr('data-script-created-date'))
      const dailyAvg = createDays > 0 ? totalInstalls / createDays : 0

      stats.maxDailyInstalls = Math.max(stats.maxDailyInstalls, dailyInstalls)
      stats.maxTotalInstalls = Math.max(stats.maxTotalInstalls, totalInstalls)
      stats.maxGoodRatings = Math.max(stats.maxGoodRatings, goodRating)
      stats.maxDailyAvgInstalls = Math.max(stats.maxDailyAvgInstalls, dailyAvg)
    })

    this.globalStats = stats
  }

  /**
   * 处理单个脚本元素
   */
  processScriptElement($element: JQuery<HTMLElement>): void {
    // 检查是否已经处理过（避免重复处理）
    if ($element.data(this.dataAttrs.processed.name))
      return

    $element.data(this.dataAttrs.processed.name, true)
    this.tracker.dataAttrs($element, this.dataAttrs.processed.type, this.dataAttrs.processed.name)

    const data: IScriptData = this.scriptProcessor.getScriptData($element)

    // 计算评分
    let score = this.calculateFinalScore(data)
    $element.attr(this.dataAttrs.score.name, score.toFixed(1))
    this.tracker.dataAttrs($element, this.dataAttrs.score.type, this.dataAttrs.score.name)

    // 创建容器
    const $metaContainer = $('<div>').addClass(this.CONTAINER_CLASS)
    this.tracker.creation($metaContainer)

    // 添加评分显示
    const $scoreElement = this.createScoreElement(score, data.dailyAvgInstalls)
    this.tracker.creation($scoreElement)

    // 生成标签
    const tags = this.generateTags({
      score,
      goodRating: data.goodRating,
      dailyInstalls: data.dailyInstalls,
      totalInstalls: data.totalInstalls,
      dailyAvgInstalls: data.dailyAvgInstalls,
      lastUpdatedDays: data.lastUpdatedDays,
      createDays: data.createDays,
      isMine: data.isMine,
    })

    // 应用保底分数
    score = this.applyTagScoreRules(score, tags)

    if (tags.length > 0) {
      const $tagsContainer = $('<div>').addClass('script-tags-container')
      this.tracker.creation($tagsContainer)

      tags.forEach((tag) => {
        const label = this.getTagLabel(tag)
        const $tagElement = $('<span>')
          .addClass(`script-tag ${tag}`)
          .attr('data-type', tag)
          .text(label)
        $tagElement.appendTo($tagsContainer)
        this.tracker.creation($tagElement)
      })
      $metaContainer.append($tagsContainer)
    }

    // 获取评分等级
    const scoreLevel = this.getScoreLevel(score)

    // 更新评分并设置颜色类别
    $scoreElement.find('.score-value').text(score)
    $scoreElement.find('.score-ring').attr('data-score', scoreLevel.level)

    // 更新奖牌图标
    const medalIcon = this.getScoreMedalIcon(scoreLevel.level)
    $scoreElement.find('.score-medal').text(medalIcon)
    $metaContainer.prepend($scoreElement)

    // 插入到 DOM
    $element.find('article').prepend($metaContainer)

    // 更新用户头像
    this.scriptProcessor.updateAvatar($element)
  }

  /**
   * 创建环形评分显示元素
   */
  createScoreElement(score: number, dailyAvgInstalls: number): JQuery<HTMLElement> {
    // 计算环形进度条的周长和偏移量
    const circumference = 2 * Math.PI * 40
    const offset = circumference - (score / 100) * circumference

    return $(`
      <div class="script-score-container">
        <!-- 环形评分图（左侧） -->
        <div class="score-ring">
          <svg class="score-svg" viewBox="0 0 100 100">
            <circle class="score-circle-bg" cx="50" cy="50" r="40"/>
            <circle 
              class="score-circle-fg" 
              cx="50" 
              cy="50" 
              r="40"
              stroke-dasharray="${circumference}"
              stroke-dashoffset="${offset}"
            />
          </svg>
          <span class="score-value">${score}</span>
        </div>
        
        <!-- 辅助信息（右侧） -->
        <div class="score-meta">
          <span class="score-total">/100</span>
          <span class="daily-avg">(日均安装量：${dailyAvgInstalls})</span>
          <span class="score-medal"></span>
        </div>
      </div>
    `)
  }

  /**
   * 处理满分脚本的最终评分
   */
  calculateFinalScore(scriptData: IScriptData): number {
    // 先计算基础分数
    let score = this.calculateScore(scriptData)

    // 如果是满分(100)，需要额外检查
    if (score === 100) {
      // 满分脚本必须满足所有条件：
      // 1. 近期更新（30天内）
      // 2. 日安装量 > 100
      // 3. 好评率 > 85%
      const totalRatings = scriptData.goodRating + scriptData.okRating + scriptData.badRating
      const goodRatingPercent = totalRatings > 0
        ? scriptData.goodRating / totalRatings * 100
        : 0

      if (scriptData.lastUpdatedDays > 30
        || scriptData.dailyInstalls <= 100
        || goodRatingPercent <= 70) {
        score = 95 // 不满足条件降为95分
      }
    }

    // 应用活跃度惩罚
    const activityPenalty = this.calculateActivityPenalty(scriptData)
    score += activityPenalty

    // 应用安装量限制
    if (scriptData.totalInstalls < 1000000) {
      score = Math.min(score, 89)
    }
    if (scriptData.totalInstalls < 500000) {
      score = Math.min(score, 84)
    }
    if (scriptData.totalInstalls < 100000) {
      score = Math.min(score, 79)
    }

    return Math.max(50, Math.min(score, 100))
  }

  /**
   * 计算脚本综合评分 (0-100)
   * 1）https://greasyfork.org/zh-CN/scripts/488083
   */
  calculateScore(scriptData: IScriptData): number {
    // 基础评分(0-40分)
    const totalRatings = scriptData.goodRating + scriptData.okRating + scriptData.badRating
    const ratingScore = totalRatings > 0
      ? (scriptData.goodRating * 1.2 + scriptData.okRating * 0.3 - scriptData.badRating * 0.1)
      / Math.max(totalRatings, 10) * 40
      : 20 // 默认中位数

    // 安装量加成 (0-40分) - 提高权重
    const installScore = Math.min(
      // 日安装量（低于100时平滑处理）
      (scriptData.dailyInstalls < 100
        ? Math.sqrt(scriptData.dailyInstalls + 1) * 3
        : Math.log10(scriptData.dailyInstalls + 1) * 6)
      // 总安装量（超高安装直接满分）
      + (scriptData.totalInstalls > 1000000
        ? 15
        : Math.log10(scriptData.totalInstalls + 1) * 4)
      // 日均安装量
      + Math.log10(scriptData.dailyAvgInstalls + 1) * 8,
      40,
    )

    // 更新频率加成 (0-20分) - 时间衰减
    const updateScore = scriptData.lastUpdatedDays <= 7
      ? 20
      : scriptData.lastUpdatedDays <= 30
        ? 15
        : scriptData.lastUpdatedDays <= 90
          ? 10
          : scriptData.lastUpdatedDays <= 180 ? 5 : 0 // 超过半年不得分

    // 安装量特别高的奖励分
    const massAdoptionBonus = scriptData.totalInstalls > 1000000
      ? 15
      : scriptData.totalInstalls > 500000 ? 10 : 0

    return Math.max(50, Math.min(
      Math.round(ratingScore + installScore + updateScore + massAdoptionBonus),
      100,
    ))
  }

  /**
   * 检查脚本活跃度并计算惩罚分
   */
  private calculateActivityPenalty(scriptData: IScriptData): number {
    let penalty = 0

    // 超过1年未更新
    if (scriptData.lastUpdatedDays > 365) {
      penalty -= 2 // 加大惩罚力度
    }

    // 日安装量为0
    if (scriptData.dailyInstalls === 0) {
      penalty -= 2 // 新增日安装量为0的惩罚
    }

    // 超过半年未更新且日安装量为0
    if (scriptData.lastUpdatedDays > 180 && scriptData.dailyInstalls === 0) {
      penalty -= 1 // 额外叠加惩罚
    }

    return penalty
  }

  /**
   * 生成脚本标签
   */
  generateTags(scriptData: IScriptRank): string[] {
    const tags: string[] = []

    if (scriptData.score >= 85 && scriptData.totalInstalls > 100000 && scriptData.dailyInstalls > 300 && scriptData.dailyAvgInstalls > 100) {
      tags.push(SCRIPT_TAG_LABELS.highQuality.value)
    }

    if ((scriptData.dailyInstalls > 300 || scriptData.totalInstalls > 100000) && scriptData.dailyAvgInstalls > 100 && scriptData.lastUpdatedDays < 365) {
      tags.push(SCRIPT_TAG_LABELS.popular.value)
    }

    if (scriptData.lastUpdatedDays <= 7) {
      tags.push(SCRIPT_TAG_LABELS.frequentlyUpdated.value)
    }
    else if (scriptData.lastUpdatedDays <= 30 && scriptData.score >= 75) {
      tags.push(SCRIPT_TAG_LABELS.recommended.value)
    }

    if (scriptData.createDays <= 14) {
      tags.push(SCRIPT_TAG_LABELS.new.value)
    }

    // 日安装量大于50
    if (scriptData.dailyInstalls === this.globalStats.maxDailyInstalls && scriptData.dailyInstalls > 50) {
      tags.push(SCRIPT_TAG_LABELS.dailyInstallTop.value)
    }

    // 总安装量大于1万
    if (scriptData.totalInstalls === this.globalStats.maxTotalInstalls && scriptData.totalInstalls > 10000) {
      tags.push(SCRIPT_TAG_LABELS.totalInstallTop.value)
    }

    // 好评大于100
    if (scriptData.goodRating === this.globalStats.maxGoodRatings && scriptData.goodRating > 100) {
      tags.push(SCRIPT_TAG_LABELS.goodRatingTop.value)
    }

    // 日均安装量大于50
    if (scriptData.dailyAvgInstalls === this.globalStats.maxDailyAvgInstalls && scriptData.dailyAvgInstalls > 50) {
      tags.push(SCRIPT_TAG_LABELS.dailyAvgInstallTop.value)
    }

    // 我的脚本
    if (scriptData.isMine) {
      tags.push(SCRIPT_TAG_LABELS.mine.value)
    }

    // 应用互斥规则
    return this.applyExclusiveRules(tags)
  }

  /**
   * 应用标签互斥规则
   */
  private applyExclusiveRules(tags: string[]): string[] {
    const finalTags = [...tags]

    TAG_EXCLUSIVE_RULES.forEach((rule) => {
      // 如果包含主标签
      if (finalTags.includes(rule.primary)) {
        // 移除所有互斥标签
        rule.excluded.forEach((excludedTag) => {
          const index = finalTags.indexOf(excludedTag)
          if (index > -1) {
            finalTags.splice(index, 1)
          }
        })
      }
    })

    return finalTags
  }

  /**
   * 应用标签保底分数规则
   */
  private applyTagScoreRules(score: number, tags: string[]): number {
    let adjustedScore = score

    // 有任意标签的最低分
    if (tags.length > 0 && adjustedScore < TAG_MIN_SCORES.default) {
      adjustedScore = TAG_MIN_SCORES.default
    }

    // 特殊标签保底分数
    for (const [tag, minScore] of Object.entries(TAG_MIN_SCORES)) {
      if (tag !== 'default' && tags.includes(SCRIPT_TAG_LABELS[tag as keyof typeof SCRIPT_TAG_LABELS]?.value)) {
        adjustedScore = Math.max(adjustedScore, minScore)
      }
    }

    return adjustedScore
  }

  /**
   * 获取评分等级信息
   */
  private getScoreLevel(score: number): {
    level: keyof typeof SCORE_LEVELS
    color: string
    label: string
  } {
    for (const [level, config] of Object.entries(SCORE_LEVELS)) {
      if (score >= config.min) {
        return {
          level: level as keyof typeof SCORE_LEVELS,
          color: config.color,
          label: config.label,
        }
      }
    }

    return {
      level: 'low',
      color: SCORE_LEVELS.low.color,
      label: SCORE_LEVELS.low.label,
    }
  }

  /**
   * 获取标签显示文本
   */
  getTagLabel(tag: string): string {
    // 查找匹配的标签项
    const matchedLabel = Object.values(SCRIPT_TAG_LABELS).find(
      item => item.value === tag,
    )

    // 返回找到的标签文本或原标签
    return matchedLabel?.label || tag
  }

  /**
   * 根据评分获取对应奖牌图标
   */
  private getScoreMedalIcon(level: ScoreLevelType): string {
    switch (level) {
      case 'high':
        return SYMBOLS.RATING.GOLD
      case 'medium':
        return SYMBOLS.RATING.SILVER
      case 'low':
      default:
        return SYMBOLS.RATING.BRONZE
    }
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)

    this.processAllScriptElements()

    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }

  getStyles(): string {
    return `
/* 脚本元数据容器 */
.${this.CONTAINER_CLASS} {
  display: flex;
  flex-direction: row;
  gap: 8px;
  margin-bottom: 12px;
  align-items: center;
}

.script-score-container {
  display: flex;
  align-items: center;
  gap: 8px;
  
  .score-ring {
    position: relative;
    width: 60px;
    height: 60px;
  }
  
  .score-svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
  }
  
  .score-circle-bg {
    fill: none;
    stroke: none;
    stroke-width: 6;
  }
  
  .score-circle-fg {
    fill: none;
    stroke: #3a7bd5;
    stroke-width: 6;
    stroke-linecap: round;
    transition: stroke-dashoffset 0.5s ease;
  }
  
  .score-value {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 18px;
    font-weight: 700;
    color: #3a7bd5;
  }
  
  .score-total {
    font-size: 14px;
    color: #666;
  }
  
  .daily-avg {
    font-size: 14px;
  }
  
  /* 根据评分改变环形颜色 */
  .score-ring[data-score="high"] .score-circle-fg {
    stroke: #4CAF50; /* 高分绿色 */
  }
  
  .score-ring[data-score="medium"] .score-circle-fg {
    stroke: #FFC107; /* 中分黄色 */
  }
  
  .score-ring[data-score="low"] .score-circle-fg {
    stroke: #F44336; /* 低分红色 */
  }
}
`
  }
}
